package com.matrix.marketing.service.impl;

import com.matrix.api.marketing.vo.CheckInResultVO;
import com.matrix.api.marketing.vo.UserCouponVO;
import com.matrix.api.marketing.vo.UserPointsVO;
import com.matrix.common.enums.CouponStatusEnum;
import com.matrix.common.exception.BusinessException;
import com.matrix.marketing.constant.MarketingConstants;
import com.matrix.marketing.converter.MarketingConverter;
import com.matrix.marketing.entity.*;
import com.matrix.marketing.mapper.UserCouponMapper;
import com.matrix.marketing.service.*;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author 有点甜
 * @since 2025/8/1
 */
@Service
@RequiredArgsConstructor
public class MarketingUserServiceImpl implements MarketingUserService {

    private final UserCheckInService userCheckInService;
    private final UserCouponService userCouponService;
    private final CouponTemplateService couponTemplateService;
    private final UserCouponMapper userCouponMapper;
    private final UserPointsService userPointsService;
    private final PointsLogService pointsLogService;
    private final RedissonClient redissonClient;
    private final Random random = new Random();

    @Override
    @Transactional
    public CheckInResultVO userCheckIn(Long userId) {
        String lockKey = "lock:checkin:" + userId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            boolean isLocked = lock.tryLock(3, 10, TimeUnit.SECONDS);

            if (!isLocked) {
                throw new BusinessException("操作频繁,请稍后再试");
            }

            LocalDate today = LocalDate.now();
            UserCheckIn checkIn = userCheckInService.lambdaQuery().eq(UserCheckIn::getUserId, userId).one();

            int continuousDays = 1;
            if (checkIn != null) {
                if (checkIn.getLastCheckInDate().isEqual(today)) {
                    throw new BusinessException("今日已签到");
                }
                if (checkIn.getLastCheckInDate().isEqual(today.minusDays(1))) {
                    continuousDays = checkIn.getContinuousDays() + 1;
                }
                checkIn.setLastCheckInDate(today);
                checkIn.setContinuousDays(continuousDays);
                userCheckInService.updateById(checkIn);
            } else {
                checkIn = new UserCheckIn();
                checkIn.setUserId(userId);
                checkIn.setLastCheckInDate(today);
                checkIn.setContinuousDays(continuousDays);
                userCheckInService.save(checkIn);
            }

            CheckInResultVO result = new CheckInResultVO();
            result.setContinuousDays(continuousDays);

            double probability = Math.min(0.1 + (continuousDays - 1) * 0.05, 0.8);
            if (random.nextDouble() < probability) {
                int randomIndex = random.nextInt(MarketingConstants.CHECK_IN_COUPON_TEMPLATE_IDS.size());
                long templateId = MarketingConstants.CHECK_IN_COUPON_TEMPLATE_IDS.get(randomIndex);
                CouponTemplate template = couponTemplateService.getById(templateId);
                if (template != null) {
                    UserCoupon userCoupon = new UserCoupon();
                    userCoupon.setUserId(userId);
                    userCoupon.setTemplateId(templateId);
                    userCoupon.setObtainTime(LocalDateTime.now());
                    userCoupon.setExpireTime(LocalDateTime.now().plusDays(template.getValidDays()));
                    userCoupon.setStatus(CouponStatusEnum.UNUSED);
                    userCouponService.save(userCoupon);

                    result.setHasCoupon(true);
                    result.setCouponTitle(template.getTitle());
                }
            }
            return result;

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new BusinessException("系统中断,请重试");
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public List<UserCouponVO> getMyCoupons(Long userId, Long shopId) {
        return userCouponMapper.findAvailableCoupons(userId, shopId, LocalDateTime.now());
    }

    @Override
    public UserPointsVO getMyPoints(Long userId) {
        UserPoints userPoints = userPointsService.lambdaQuery().eq(UserPoints::getUserId, userId).one();
        UserPointsVO vo = new UserPointsVO();
        vo.setTotalPoints(userPoints != null ? userPoints.getTotalPoints() : 0L);
        return vo;
    }

    @Override
    @Transactional
    public UserCouponVO exchangeCouponWithPoints(Long userId, int pointsToUse) {
        String lockKey = "lock:exchange_points:" + userId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            if (!lock.tryLock(3, 10, TimeUnit.SECONDS)) {
                throw new BusinessException("系统繁忙,请稍后重试");
            }

            final long templateId;

            final String description = switch (pointsToUse) {
                case 50 -> {
                    templateId = MarketingConstants.POINTS_EXCHANGE_COUPON_50;
                    yield "50积分兑换无门槛7元券";
                }
                case 100 -> {
                    templateId = MarketingConstants.POINTS_EXCHANGE_COUPON_100;
                    yield "100积分兑换无门槛15元券";
                }
                case 200 -> {
                    templateId = MarketingConstants.POINTS_EXCHANGE_COUPON_200;
                    yield "200积分兑换无门槛30元券";
                }
                default -> throw new BusinessException("无效的兑换选项");
            };

            CouponTemplate template = couponTemplateService.getById(templateId);
            if (template == null || template.getStatus() != 1) {
                throw new BusinessException("该兑换项已下架");
            }

            UserPoints userPoints = userPointsService.lambdaQuery().eq(UserPoints::getUserId, userId).one();
            if (userPoints == null || userPoints.getTotalPoints() < pointsToUse) {
                throw new BusinessException("您的积分不足");
            }

            userPoints.setTotalPoints(userPoints.getTotalPoints() - pointsToUse);
            boolean success = userPointsService.updateById(userPoints);
            if (!success) {
                throw new BusinessException("系统繁忙,兑换失败,请稍后重试");
            }

            PointsLog log = new PointsLog();
            log.setUserId(userId);
            log.setPointsChange(-pointsToUse);
            log.setCurrentPoints(userPoints.getTotalPoints());
            log.setSourceType(3);
            log.setSourceId(String.valueOf(templateId));
            log.setDescription(description);
            pointsLogService.save(log);

            UserCoupon newUserCoupon = new UserCoupon();
            newUserCoupon.setUserId(userId);
            newUserCoupon.setTemplateId(template.getId());
            newUserCoupon.setStatus(CouponStatusEnum.UNUSED);
            newUserCoupon.setObtainTime(LocalDateTime.now());
            newUserCoupon.setExpireTime(LocalDateTime.now().plusDays(template.getValidDays()));
            userCouponService.save(newUserCoupon);

            return MarketingConverter.INSTANCE.toUserCouponVO(newUserCoupon, template);

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new BusinessException("系统中断,请重试");
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
